package com.mall.user.application.service;

import com.mall.user.domain.command.CreateUserCommand;
import com.mall.user.domain.event.UserCreatedEvent;
import com.mall.user.domain.exception.UserCreationException;
import com.mall.user.domain.port.in.CreateUserUseCase;
import com.mall.user.domain.port.out.CreateUserPort;
import com.mall.user.domain.service.UserDomainService;
import com.mall.user.domain.model.User;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 创建用户应用服务
 * 专注于业务流程编排和数据持久化
 * 所有业务校验逻辑已下沉到domain层
 */
@Slf4j
@Service
public class CreateUserService implements CreateUserUseCase {

    @Resource
    private CreateUserPort createUserPort;
    
    @Resource
    private UserDomainService userDomainService;
    
    @Resource
    private ApplicationEventPublisher eventPublisher;
    
    @Override
    @Transactional
    public User createUser(CreateUserCommand command) {
        log.info("应用服务开始处理创建用户请求，用户名: {}", command.name().name());
        
        try {
            // 1. 通过领域工厂方法创建用户（包含所有业务校验）
            User user = User.createNewUser(command, userDomainService);
            
            // 2. 持久化用户
            createUserPort.createUser(user);
            
            // 3. 发布用户创建事件
            publishUserCreatedEvent(user);
            
            log.info("用户创建成功，用户名: {}, ID: {}", command.name().name(), user.getId());
            return user;
            
        } catch (IllegalArgumentException | com.mall.user.domain.exception.UserAlreadyExistsException e) {
            // 业务异常直接向上抛出，由全局异常处理器处理
            log.warn("用户创建失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            // 技术异常包装为业务异常
            log.error("用户持久化失败，用户名: {}", command.name().name(), e);
            throw new UserCreationException("用户创建失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 发布用户创建事件
     * @param user 创建的用户
     */
    private void publishUserCreatedEvent(User user) {
        try {
            UserCreatedEvent event = new UserCreatedEvent(this, user);
            eventPublisher.publishEvent(event);
            log.info("用户创建事件发布成功: userId={}, userName={}", user.getId(), user.getName().name());
        } catch (Exception e) {
            // 事件发布失败不应该影响主业务流程
            log.error("用户创建事件发布失败: userId={}, userName={}, error={}", 
                    user.getId(), user.getName().name(), e.getMessage(), e);
        }
    }
}
